package com.lg.aop;

import com.lg.annotation.MyTransaction;
import com.lg.utils.TransactionUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.lang.reflect.Method;

/**
 * 注解方式的 aop拦截
 *
 * @author by Mr. Li 2020/9/9 12:04
 */
@Component
@Aspect
public class AopExtTransaction {
    @Autowired
    private TransactionUtil transactionUtil;

    // 环绕通知在方法之前和之后处理事情
    @Around("execution( * com.lg.service.impl.*.*.*(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 1. 获取代理对象的方法
        String methodName = proceedingJoinPoint.getSignature().getName();
        // 获取目标对象
        Class<?> aClass = proceedingJoinPoint.getTarget().getClass();
        Class[] parameterTypes = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterTypes();

        // 获取目标对象方法
        Method method = aClass.getMethod(methodName, parameterTypes);

        // 判断获取到的方法上是否有添加注解，如果存在注解，则需要开启事务
        MyTransaction annotation = method.getAnnotation(MyTransaction.class);

        TransactionStatus transactionStatus = null;

        if (annotation != null) {
            transactionStatus = transactionUtil.begin();
        }

        // 环绕通知之前
        proceedingJoinPoint.proceed();

        // 如果事务正常提交。则手动commit
        if (annotation != null) {
            transactionUtil.commit(transactionStatus);
        }
    }

    /**
     * 异常通知
     */
    @AfterThrowing("execution(* com.lg.service.impl.*.*.*(..))")
    public void afterThrowing(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("异常通知");
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}
